/**
 * @BelongsProject: hmall-micro
 * @BelongsPackage: com.hmall.search.service.impl
 * @Author: 王明天
 * @CreateTime: 2025/2/16 18:00
 * @Description: SearchServiceImpl
 */
package com.hmall.search.service.impl;


import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.hmall.api.item.dto.ItemDTO;
import com.hmall.common.exception.CommonException;
import com.hmall.common.utils.CollUtils;
import com.hmall.search.domain.dto.PageDTO;
import com.hmall.search.query.ItemPageQuery;
import com.hmall.search.service.ISearchService;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class SearchServiceImpl implements ISearchService {


    private final RestHighLevelClient esClient;

    /**
     * 查询商品
     *
     * @param query
     * @return
     */
    @Override
    public PageDTO<ItemDTO> search(ItemPageQuery query) {

        PageDTO<ItemDTO> pageDTO = new PageDTO<>();

        //判断是否有关键字
        if (StrUtil.isBlank(query.getKey())) {
            throw new CommonException("关键字不能为空", 400);
        }

        //创建搜索对象
        SearchRequest searchRequest = new SearchRequest("items");

        //构建搜索条件
        //分页
        searchRequest.source().from(query.from());
        searchRequest.source().size(query.getPageSize());

        //排序
        if (StrUtil.isNotBlank(query.getSortBy())) {
            searchRequest.source().sort(query.getSortBy(), query.getIsAsc() ? SortOrder.ASC : SortOrder.DESC);
        }

        //使用bool聚合查询
        //构建bool查询对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //构建查询条件
        boolQuery.must(QueryBuilders.matchQuery("name", query.getKey()));

        if (StrUtil.isNotBlank(query.getBrand())) {

            //品牌不为空才会构建条件
            boolQuery.filter(QueryBuilders.termQuery("brand", query.getBrand()));

        }

        if (StrUtil.isNotBlank(query.getCategory())) {

            //分类不为空才会构建条件
            boolQuery.filter(QueryBuilders.termQuery("category", query.getCategory()));
        }

        if (query.getMinPrice() != null && query.getMaxPrice() != null) {

            //价格范围不为空才会构建条件
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(query.getMinPrice()).lte(query.getMaxPrice()));
        }

        //构建高亮
        //创建高亮对象
        HighlightBuilder highlightBuilder = new HighlightBuilder();

        //构建查询条件
        highlightBuilder.field("name").preTags("<span style = 'color:red'>").postTags("</span>");
        searchRequest.source().highlighter();


        //执行查询
        SearchResponse searchResponse;
        try {
            searchRequest.source().query(boolQuery);
            searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException("查询失败,异常是：" + e);
        }

        //查询到的总记录数

        long value = searchResponse.getHits().getTotalHits().value;
        pageDTO.setTotal(value);
        System.out.println("查询到的总记录数为：" + value);

        //查询到的商品信息
        SearchHit[] hits = searchResponse.getHits().getHits();

        List<ItemDTO> itemDtoList = new ArrayList<>();


        //遍历数组
        for (SearchHit hit : hits) {

            //得到的是JSON字符串
            String jsonStr = hit.getSourceAsString();

            //JSON反序列化
            ItemDTO itemDto = JSONUtil.toBean(jsonStr, ItemDTO.class);

            //处理高亮结果
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();

            if (MapUtil.isNotEmpty(highlightFields)) {

                HighlightField names = highlightFields.get("name");

                if (ObjectUtil.isNotEmpty(names)) {

                    Text[] fragments = names.getFragments();

                    if (fragments != null || fragments.length > 0) {

                        itemDto.setName(fragments[0].toString());
                    }
                }
            }

            itemDtoList.add(itemDto);

        }

        pageDTO.setList(itemDtoList);

        return pageDTO;
    }

    /**
     * 搜索过滤项
     *
     * @param query
     * @return Map<String, List < String>>
     */
    @Override
    public Map<String, List<String>> filters(ItemPageQuery query) {

        //判断是否有关键字
        if (StrUtil.isBlank(query.getKey())) {
            throw new CommonException("关键字不能为空", 400);
        }

        //创建搜索对象
        SearchRequest searchRequest = new SearchRequest("items");

        //构建搜索条件
        //分页
        searchRequest.source().size(0);

        //使用bool聚合查询
        //构建bool查询对象
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //构建查询条件
        boolQuery.must(QueryBuilders.matchQuery("name", query.getKey()));

        if (StrUtil.isNotBlank(query.getBrand())) {

            //品牌不为空才会构建条件
            boolQuery.filter(QueryBuilders.termQuery("brand", query.getBrand()));

        }

        if (StrUtil.isNotBlank(query.getCategory())) {

            //分类不为空才会构建条件
            boolQuery.filter(QueryBuilders.termQuery("category", query.getCategory()));
        }

        if (query.getMinPrice() != null && query.getMaxPrice() != null) {

            //价格范围不为空才会构建条件
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(query.getMinPrice()).lte(query.getMaxPrice()));
        }

        searchRequest.source().query(boolQuery);

        //构建bool聚合查询
        searchRequest.source().aggregation(AggregationBuilders.terms("brandAgg").field("brand").size(20));
        searchRequest.source().aggregation(AggregationBuilders.terms("categoryAgg").field("category").size(20));


        //执行查询
        SearchResponse searchResponse;
        try {

            searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            throw new RuntimeException("查询失败,异常是：" + e);
        }

        Map<String, List<String>> map = new HashMap<>();

        //获取到查询结中的Aggregations
        Aggregations aggregations = searchResponse.getAggregations();

        //获取到Aggregations中的各个桶
        //获取品牌
        Terms brandAgg = aggregations.get("brandAgg");
        List<? extends Terms.Bucket> brandAggBuckets = brandAgg.getBuckets();
        List<String> brandList = new ArrayList<>();

        //判断是否为空
        if (CollUtils.isNotEmpty(brandAggBuckets)) {

            for (Terms.Bucket brandAggBucket : brandAggBuckets) {
                brandList.add(brandAggBucket.getKeyAsString());
            }
        }


        map.put("brand", brandList);

        //获取分类
        Terms categoryAgg = aggregations.get("categoryAgg");
        List<? extends Terms.Bucket> categoryAggBuckets = categoryAgg.getBuckets();

        List<String> categoryList = new ArrayList<>();

        //判断是否为空
        if (CollUtils.isNotEmpty(categoryAggBuckets)) {

            for (Terms.Bucket categoryAggBucket : categoryAggBuckets) {
                categoryList.add(categoryAggBucket.getKeyAsString());
            }

        }

        map.put("category",categoryList);

        return map;



    }
}